﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System.Collections.Generic;
using System.Collections.ObjectModel;
using Sebarf.Security.Interfaces;
using Sebarf.Services.Interfaces;

#endregion

namespace Sebarf.Security.Authorization {
	/// <summary>
	/// rights are handled based on the current <see cref="IIdentitity"/>.Id
	/// </summary>
	public class AuthorizationService : Service, IAuthorizationService {
		#region Public Properties

		[ServiceRequest]
		public IAuthenticationManagementService AuthenticationManagementService { get; set; }

		/// <summary>
		/// a list of access rules
		/// </summary>
		public ObservableCollection<IAccessRule> AccessRules { get; set; }

		/// <summary>
		/// get or sets the permission mode
		/// </summary>
		public DefaultPolicy DefaultPolicy { get; set; }

		#endregion

		#region Public Methods

		public AuthorizationService() {
			AccessRules = new ObservableCollection<IAccessRule>();
		}

		#endregion

		#region IAuthorizationService Members

		public bool CheckAccess(string action, Dictionary<string, object> args) {
			IIdentitity identity = AuthenticationManagementService.GetIdentity();
			if (identity == null || !identity.IsAuthenticated) {
				return false;
			}
			foreach (IAccessRule rule in AccessRules) {
				if (rule.IsValidForAction(action)) {
					if (!rule.CanPerformAction(action, args, identity.Id)) {
						return false;
					}
				}
			}
			if (DefaultPolicy == DefaultPolicy.DenyEverthingOnDefault) {
				return false;
			}
			return true;
		}

		#endregion
	}

	public enum DefaultPolicy {
		/// <summary>
		/// Access is denied, if not explicitly allowed
		/// </summary>
		DenyEverthingOnDefault,
		/// <summary>
		/// Access is allowed, if not explicitly denied
		/// </summary>
		AllowEverthingOnDefault
	}

	/// <summary>
	/// Valid for action: ReadField
	/// Is the user able to read the content of a given field: args[FieldName]
	/// </summary>
	public class ReadDataFieldAccessRule : IAccessRule {
		#region Public Properties

		/// <summary>
		/// Gets or sets the field that this rule applies
		/// </summary>
		public string FieldName { get; set; }

		/// <summary>
		/// Gets or sets the user id that this rule applies
		/// </summary>
		public string UserId { get; set; }

		/// <summary>
		/// Gets or sets the rule mode
		/// </summary>
		public ReadDataFieldAccessRuleMode AccessMode { get; set; }

		#endregion

		#region IAccessRule Members

		public bool IsValidForAction(string action) {
			return action == "ReadField";
		}

		public bool CanPerformAction(string action, Dictionary<string, object> args, string userId) {
			if (UserId == userId && IsValidForAction(action) && (args.ContainsKey("FieldName")) &&
				args["FieldName"].ToString() == FieldName) {
				return (AccessMode == ReadDataFieldAccessRuleMode.AllowAccess ? true : false);
			}
			return true;
		}

		#endregion
	}

	public enum ReadDataFieldAccessRuleMode {
		/// <summary>
		/// read access is denied
		/// </summary>
		DenyAccess,

		/// <summary>
		/// read access is allowed
		/// </summary>
		AllowAccess
	}

	/// <summary>
	/// Represents an access rule
	/// checks if a given user can perfom an action or not
	/// </summary>
	public interface IAccessRule {
		/// <summary>
		/// can rule apply for the given action
		/// </summary>
		/// <param name="action"></param>
		/// <returns></returns>
		bool IsValidForAction(string action);

		/// <summary>
		/// is the given user able to perform the given action
		/// </summary>
		/// <param name="action"></param>
		/// <param name="args"></param>
		/// <param name="userId"></param>
		/// <returns></returns>
		bool CanPerformAction(string action, Dictionary<string, object> args, string userId);
	}
}